/**
 * 讯飞星火语音听写流式 WebAPI 接口调用示例 - Node.js版本
 * 
 * 本demo参考Python版本实现，适用于：Node.js环境
 * 依赖库：
 * - ws (WebSocket)
 * - fs (文件系统)
 * - crypto (加密)
 */

const fs = require('fs');
const crypto = require('crypto');
const WebSocket = require('ws');
const { promisify } = require('util');
const sleep = promisify(setTimeout);

// 状态常量定义
const STATUS_FIRST_FRAME = 0;  // 第一帧的标识
const STATUS_CONTINUE_FRAME = 1;  // 中间帧标识
const STATUS_LAST_FRAME = 2;  // 最后一帧的标识

/**
 * WebSocket参数类
 */
class WsParam {
    constructor(APPID, APIKey, APISecret, AudioFile) {
        this.APPID = APPID;
        this.APIKey = APIKey;
        this.APISecret = APISecret;
        this.AudioFile = AudioFile;
        this.iat_params = {
            "domain": "slm", 
            "language": "zh_cn", 
            "accent": "mandarin",
            "dwa": "wpgs", 
            "result": {
                "encoding": "utf8",
                "compress": "raw",
                "format": "plain"
            }
        };
    }

    /**
     * 生成URL
     */
    createUrl() {
        const url = 'ws://iat.xf-yun.com/v1';
        
        // 生成RFC1123格式的时间戳
        const now = new Date();
        const date = now.toUTCString();
        
        // 拼接字符串
        let signatureOrigin = "host: " + "iat.xf-yun.com" + "\n";
        signatureOrigin += "date: " + date + "\n";
        signatureOrigin += "GET " + "/v1 " + "HTTP/1.1";
        
        // 进行hmac-sha256进行加密
        const signatureSha = crypto.createHmac('sha256', this.APISecret)
            .update(signatureOrigin)
            .digest('base64');
        
        const authorizationOrigin = `api_key="${this.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signatureSha}"`;
        const authorization = Buffer.from(authorizationOrigin).toString('base64');
        
        // 将请求的鉴权参数组合为字典
        const v = {
            authorization: authorization,
            date: date,
            host: "iat.xf-yun.com"
        };
        
        // 拼接鉴权参数，生成url
        const urlWithParams = url + '?' + new URLSearchParams(v).toString();
        return urlWithParams;
    }
}

/**
 * 处理音频文件并发送到WebSocket
 */
async function processAudio(ws, wsParam) {
    const frameSize = 1280; // 每一帧的音频大小
    const interval = 0.04; // 发送音频间隔(单位:s)
    let status = STATUS_FIRST_FRAME; // 音频的状态信息
    
    try {
        const fileData = fs.readFileSync(wsParam.AudioFile);
        
        for (let i = 0; i < fileData.length; i += frameSize) {
            const buf = fileData.slice(i, i + frameSize);
            const audio = buf.toString('base64');
            
            // 文件结束
            if (i + frameSize >= fileData.length) {
                status = STATUS_LAST_FRAME;
            }
            
            // 第一帧处理
            if (status === STATUS_FIRST_FRAME) {
                const data = {
                    "header": {
                        "status": 0,
                        "app_id": wsParam.APPID
                    },
                    "parameter": {
                        "iat": wsParam.iat_params
                    },
                    "payload": {
                        "audio": {
                            "audio": audio,
                            "sample_rate": 16000,
                            "encoding": "raw"
                        }
                    }
                };
                
                ws.send(JSON.stringify(data));
                status = STATUS_CONTINUE_FRAME;
            }
            // 中间帧处理
            else if (status === STATUS_CONTINUE_FRAME) {
                const data = {
                    "header": {
                        "status": 1,
                        "app_id": wsParam.APPID
                    },
                    "parameter": {
                        "iat": wsParam.iat_params
                    },
                    "payload": {
                        "audio": {
                            "audio": audio,
                            "sample_rate": 16000,
                            "encoding": "raw"
                        }
                    }
                };
                
                ws.send(JSON.stringify(data));
            }
            // 最后一帧处理
            else if (status === STATUS_LAST_FRAME) {
                const data = {
                    "header": {
                        "status": 2,
                        "app_id": wsParam.APPID
                    },
                    "parameter": {
                        "iat": wsParam.iat_params
                    },
                    "payload": {
                        "audio": {
                            "audio": audio,
                            "sample_rate": 16000,
                            "encoding": "raw"
                        }
                    }
                };
                
                ws.send(JSON.stringify(data));
                break;
            }
            
            // 模拟音频采样间隔
            await sleep(interval * 1000);
        }
    } catch (error) {
        console.error('处理音频文件时出错:', error);
        ws.close();
    }
}

/**
 * 主函数
 */
function main() {
    // 测试时在此处正确填写相关信息即可运行
    const wsParam = new WsParam(
        APPID = 'bede12ef',  // 填写你的APPID
        APISecret = 'Zjc1ZmJkNGMzNmVhZDMxMWVhYTRhMjMx',  // 填写你的APISecret
        APIKey = '04433a12bb2945c2cd987f27e944b675',  // 填写你的APIKey
        AudioFile = '1.webm'  // 填写音频文件路径
    );
    
    const wsUrl = wsParam.createUrl();
    const ws = new WebSocket(wsUrl, {
        rejectUnauthorized: false  // 等同于Python中的ssl.CERT_NONE
    });
    
    // 收到websocket消息的处理
    ws.on('message', (message) => {
        const data = JSON.parse(message);
        const code = data.header.code;
        const status = data.header.status;
        
        if (code !== 0) {
            console.log(`请求错误：${code}`);
            ws.close();
        } else {
            const payload = data.payload;
            if (payload) {
                let text = payload.result.text;
                text = Buffer.from(text, 'base64').toString('utf8');
                text = JSON.parse(text);
                
                const textWs = text.ws;
                let result = '';
                
                for (const i of textWs) {
                    for (const j of i.cw) {
                        const w = j.w;
                        result += w;
                    }
                }
                
                console.log(result);
            }
            
            if (status === 2) {
                ws.close();
            }
        }
    });
    
    // 收到websocket错误的处理
    ws.on('error', (error) => {
        console.log('### error:', error);
    });
    
    // 收到websocket关闭的处理
    ws.on('close', (code, reason) => {
        console.log('### closed ###');
    });
    
    // 收到websocket连接建立的处理
    ws.on('open', () => {
        processAudio(ws, wsParam);
    });
}

// 执行主函数
if (require.main === module) {
    main();
}

module.exports = {
    WsParam,
    processAudio
};